package cn.cpf.tool.doc.pdf;

import org.apache.commons.collections4.CollectionUtils;

import javax.swing.*;
import java.util.ArrayList;
import java.util.List;

public class PDFBookmarkManager {

    static final String CR_NL = System.getProperty("line.separator");

    static final String TAB = "\t";

    private static String formatOutBookmark(List<BookmarkItem> items, int basePage) {
        StringBuilder sb = new StringBuilder();
        for (BookmarkItem item : items) {
            int level = item.getLevel();
            String sName = StringUtil.StringFilter(item.getName(), "[^\\S ]+", " ");
            sb.append(level).append(TAB).append(sName).append(TAB).append(item.getPageNumString(basePage)).append(CR_NL);
        }
        return sb.toString();
    }

    public static String getBookmarkStringFromPDF(String strFile, int basePage) {
        List<BookmarkItem> list = PDFBoxUtil.getBookmarkFromFile(strFile);
        if (CollectionUtils.isEmpty(list)) {
            return "";
        }
        return formatOutBookmark(list, basePage);
    }

    private static int getLevelFromStr(String str) {
        int len = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == ' ') {
                len++;
            } else if (str.charAt(i) == "\t".charAt(0)) {
                len += 4;
            } else if (str.charAt(i) == " ".charAt(0)) {
                len += 4;
            } else {
                break;
            }
        }
        return (len + 3) / 4;
    }

    private static ArrayList<BookmarkItem> readBookmarkFromString(String str, int basePage) throws Exception {
        String[] lines = StringUtil.StringSplit(str, "[\r\n]+");
        ArrayList<BookmarkItem> items = new ArrayList<BookmarkItem>();
        for (String line : lines) {
            line = StringUtil.removeComment(line, "#");
            if (!StringUtil.StringFilter(line, " ", " ").isEmpty()) {
                BookmarkItem item = new BookmarkItem();
                item.setLevel(getLevelFromStr(line));
                line = StringUtil.StringFilter(line, "^( |　)+|( } )+$", "");
                String[] ss = StringUtil.StringSplit(line, "(    |    | |\t)(|\t)*");
                if (ss.length >= 1) {
                    String sName = StringUtil.StringFilter(ss[0], "[\r\n\t]|   +||{2,}|(){2,}|#+", " ");
                    item.setName(sName);
                }
                if (ss.length >= 2) {
                    String s = StringUtil.filterNumber(ss[1], "/\\").trim();
                    if (StringUtil.isInteger(s)) {
                        item.setPageNum(Integer.parseInt(s) + basePage - 1);
                    } else {
                        throw new Exception("Incorrect Bookmark: \t" + line);
                    }
                }
                items.add(item);
            }
        }
        return items;
    }

    public static void saveBookmarkStringToPDF(String strFile, String str, int basePage) throws Exception {
        ArrayList<BookmarkItem> items = readBookmarkFromString(str, basePage);
        String strError = checkBookmarkError(items, basePage);
        if (!strError.isEmpty())
            JOptionPane.showMessageDialog(null, strError, "Warning", 2);
        PDFBoxUtil.saveBookmarkToFile(strFile, items, basePage);
    }

    public static int getBasePage(String bkmPage, String realPage) {
        return Integer.parseInt(realPage) - Integer.parseInt(bkmPage);
    }

    private static String checkBookmarkError(ArrayList<BookmarkItem> items, int basePage) {
        int maxLine = 20;
        StringBuilder sb = new StringBuilder();
        int cur = 0;
        int line = 0;
        for (BookmarkItem item : items) {
            boolean bFalse = true;
            if (cur < item.getLevel() - 1) {
                sb.append("Sub-Level indent incorrect: \t").append(item.getName()).append(TAB) .append(item.getPageNumString(basePage)).append(CR_NL);
            } else if (item.getName().isEmpty()) {
                sb.append("Bookmark Name is empty: \t").append(item.getName()).append(TAB) .append(item.getPageNumString(basePage)).append(CR_NL);
            } else if (item.getName().length() > 120) {
                sb.append("Bookmark Name too long: \t").append(item.getName()).append(TAB) .append(item.getPageNumString(basePage)).append(CR_NL);
            } else if (!item.isPageNumOK()) {
                sb.append("Bookmark Page not set: \t").append(item.getName()).append(TAB) .append(item.getPageNumString(basePage)).append(CR_NL);
            } else {
                bFalse = false;
            }
            line++;
            if (bFalse && line >= maxLine) {
                sb.append("......");
                break;
            }
            cur = item.getLevel();
        }
        return sb.toString();
    }

    public static int findBasePageFromString(String str) {
        int basePage = -1;
        if (!str.isEmpty()) {
            int i = str.indexOf("basePage = ");
            if (-1 != i) {
                i += "basePage = ".length();
                int j = str.indexOf(CR_NL, i);
                if (-1 == j)
                    j = str.length();
                basePage = Integer.parseInt(str.substring(i, j));
            }
        }
        return basePage;
    }
}
